library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity statemachine is
  port( start_stop_sync, lap_reset_sync, clk : in std_logic;
        is_running, is_lapped, reset : out std_logic );
end entity statemachine;

architecture statemachine_behavioral of statemachine is
--begin
--state_transition: process(start_stop_sync,lap_reset_sync,previous_state) is

type state_name is (STOPPED_AND_RESET,STARTED,LAPPED,LAPPED_AND_STOPPED,STOPPED);
type state_type is record
state: state_name;
is_running: std_logic;
is_lapped: std_logic;
reset: std_logic;
end record;

signal next_state: state_type:=(STOPPED_AND_RESET, '0','0','1');
signal previous_state: state_type:=(STOPPED_AND_RESET, '0','0','1');

begin
  
  combinational_block: process(start_stop_sync,lap_reset_sync,previous_state) is
  variable temporary_state: state_type:=(STOPPED_AND_RESET, '0','0','1');
  begin
    temporary_state:=previous_state;
    case previous_state.state is
      
    when STOPPED_AND_RESET =>
      
      if start_stop_sync='1' then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when STARTED =>
      
      if start_stop_sync='1' then
        temporary_state.state := STOPPED;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := LAPPED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when LAPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := LAPPED_AND_STOPPED;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      else
        NULL;
      end if;
      
    when LAPPED_AND_STOPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := LAPPED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '1';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STOPPED_AND_RESET;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '1';
      else
        NULL;
      end if;
      
    when STOPPED =>
      
      if start_stop_sync='1' then
        temporary_state.state := STARTED;
        temporary_state.is_running := '1';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '0';
      elsif lap_reset_sync='1'then
        temporary_state.state := STOPPED_AND_RESET;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '1';
      else
        NULL;
      end if;

    when others =>
	temporary_state.state := STOPPED_AND_RESET;
        temporary_state.is_running := '0';
        temporary_state.is_lapped := '0';
        temporary_state.reset := '1';

    end case;
    
    is_running <= temporary_state.is_running;
    is_lapped <= temporary_state.is_lapped;
    reset <= temporary_state.reset;
    next_state <= temporary_state;
    
  end process combinational_block;
  
  sequential_block: process(clk) is
  begin
    
    if rising_edge(clk) then
      previous_state <= next_state;
    end if;
  end process sequential_block;

end architecture statemachine_behavioral;
-----------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity synchronous_posedges is
  port( i, clk : in std_logic;
        o : out std_logic := '0' );
end entity synchronous_posedges;

architecture behavioral of synchronous_posedges is
begin
  spe_beh : process(clk) is
    variable last_i : std_logic := '0';
  begin
    if rising_edge(clk) then
      if i = '1' and last_i = '0' then
        o <= '1';
      else
        o <= '0';
      end if;
      last_i := i;
    end if;
  end process spe_beh;
end architecture behavioral;
---------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity state_machine_test_bench is
  port( clk : in std_logic;
        is_running,is_lapped, reset : out std_logic := '0' );
end entity state_machine_test_bench;

architecture state_machine_test_bench_arch of state_machine_test_bench is
  signal ss_sync,lr_sync:std_logic;
  signal start_stop,lap_reset:std_logic;
  begin
    
    sync1 : entity work.synchronous_posedges(behavioral) port map (start_stop, clk, ss_sync);
    sync2 : entity work.synchronous_posedges(behavioral) port map (lap_reset, clk, lr_sync);

    statm : entity work.statemachine(statemachine_behavioral) port map (ss_sync, lr_sync,clk,
                                                         is_running, is_lapped, reset);
    -- started&stopped to started&stopped
    
--    start_stop <= '0', '1' after 0.1 us, '0' after 0.2 us;
    
    -- started&stopped to started&stopped
    
    start_stop <= '0', '1' after 0.1 us, '0' after 0.2 us, '1' after 0.7 us, '0' after 0.9 us;
    lap_reset <= '0','1' after 0.4 us, '0' after 0.6 us;
    
                                                         
end architecture state_machine_test_bench_arch;
